library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.typeDefinitions.all;

entity memInterstageReg is
  port (
    clk            : in std_logic;
    nReset         : in std_logic;
    holdStage      : in std_logic;
    invalidate     : in std_logic;
	
    nPC_in         : in std_logic_vector(31 downto 0);   
	upper_in   : in std_logic_vector(31 downto 0);
    aluResult_in        : in std_logic_vector(31 downto 0);
    dataMem_in        : in std_logic_vector(31 downto 0);
    destination_in : in std_logic_vector(4 downto 0);
	
    instruction_in : in operation;

	upper   : out std_logic_vector(31 downto 0);
    aluResult       		: out std_logic_vector(31 downto 0);
    dataMem        	: out std_logic_vector(31 downto 0);
    destination 	: out std_logic_vector(4 downto 0);
    instruction 	: out operation;
    nPC         	: out std_logic_vector(31 downto 0));
end memInterstageReg;

architecture memInterstageReg_arch of memInterstageReg is

  signal r_instruction, n_instruction   : operation;
  signal r_aluResult, r_dataMem, n_aluResult, n_dataMem : std_logic_vector(31 downto 0);
  signal r_nPC, n_nPC                   : std_logic_vector(31 downto 0);
  signal r_destination      : std_logic_vector(4 downto 0);
  signal  n_destination       : std_logic_vector(4 downto 0);
  signal n_up, r_up               : std_logic_vector(31 downto 0);
  
begin  -- fetchInterstageReg  

  nPC <= r_nPC;
  instruction <= r_instruction;
  destination <= r_destination;
 
  aluResult <= r_aluResult;
  dataMem <= r_dataMem;
  upper <= r_up;

  registers : process (clk, nReset, n_nPC, n_instruction, n_aluResult, n_dataMem, n_destination)
  begin

    -- one register if statement
    if (nReset = '0') then
      -- Reset here
      
      r_instruction <= (o_nop);
      r_nPC         <= (others => '0');
      r_aluResult        <= (others => '0');
      r_dataMem        <= (others => '0');
	  r_up       <= (others => '0');
      r_destination <= (others => '0');                       
      
    elsif (falling_edge(clk)) then
      -- Set register here
      
      r_instruction <= n_instruction;
      r_nPC         <= n_nPC;
      r_aluResult        <= n_aluResult;
      r_dataMem        <= n_dataMem;    
	  r_up      <= n_up;
      r_destination <= n_destination;
      
    end if;
    
  end process;


  -- outputs: 
  nextState : process (holdStage, invalidate, r_aluResult, r_dataMem, r_instruction, r_nPC, r_destination, destination_in, nPC_in, instruction_in, aluResult_in, dataMem_in, r_up, upper_in)
  begin  -- process nextState
    if(invalidate = '1') then
      n_instruction <= o_nop;
      n_nPC         <= (others => '0');
      n_aluResult        <= (others => '0');
      n_dataMem        <= (others => '0');
	  n_up       <= (others => '0');
      n_destination <= (others => '0');
      
    else
      if(holdStage = '1') then
        n_instruction <= r_instruction;
        n_nPC         <= r_nPC;
        n_aluResult        <= r_aluResult;
        n_dataMem        <= r_dataMem;     
		n_up <= r_up;
        n_destination <= r_destination;
      else
        n_nPC         <= nPC_in;
        n_instruction <= instruction_in;
        n_aluResult   <= aluResult_in;
        n_dataMem        <= dataMem_in;      
		n_up <= upper_in;
        n_destination <= destination_in;
      end if;
    end if;
    
    
  end process nextState;

  

end memInterstageReg_arch;
